package types

import (
	"fmt"
	"gitee.com/sunliang711/locker-control/server/utils"
	"github.com/gorilla/mux"
	"net/http"
	"strconv"
	"time"
)

const (
	RespOK int = iota
	RespError
)

const (
	MsgOpenSuccess   = "Open Locker [%v-%v] OK"
	MsgOpenFailed    = "Open Locker [%v-%v] Failed"
	MsgIdError       = "Client Id [%v] Not Exist"
	MsgChannelError  = "Locker Number [%v] Error"
	MsgStatusOK      = "Query Locker [%v-%v] Status OK"
	MsgStatusError   = "Query Locker [%v-%v] Status Failed"
	MsgOpenTimeout   = "Open Locker [%v-%v] Timeout"
	MsgStatusTimeout = "Query Locker [%v-%v] Timeout"
	MsgPeersOK       = "Query peers ok"
)
const (
	Success = 0
)
const (
	StatusLockerOpen int = iota
	StatusLockerClose
)

func getId(r *http.Request) (string, error) {

	vars := mux.Vars(r)
	id := vars["id"]
	if Peers[id] == nil {
		return "", fmt.Errorf("Id: %v not exist in Peers", id)
	}
	return id, nil
}

func getChannel(r *http.Request) (byte, error) {
	vars := mux.Vars(r)
	channel := vars["channel"]
	t, err := strconv.Atoi(channel)
	if err != nil {
		return 0, err
	}
	return byte(t), nil

}

//srv.Router.HandleFunc("/open/{id}/{channel}",LockerOpen)
func LockerOpen(w http.ResponseWriter, r *http.Request) {
	id, err := getId(r)
	if err != nil {
		openLog.Printf("Get Id error: %v", err.Error())
		utils.JsonResponse(w, http.StatusBadRequest, RespError, fmt.Sprintf(MsgIdError, mux.Vars(r)["id"]), nil)
		return
	}
	peer := Peers[id]

	channel, err := getChannel(r)
	if err != nil {
		openLog.Printf("Get channel error: %v", err)
		utils.JsonResponse(w, http.StatusBadRequest, RespError, fmt.Sprintf(MsgChannelError, mux.Vars(r)["channel"]), nil)
	}

	var (
		frame *Frame
	)
	switch ProtocolVersion {
	case Version2G:
		frame = NewFrame(CmdOpen2G, []byte{channel})
	case Version4G:
		frame = NewFrame(CmdOpen4G, []byte{channel})
	}
	n, err := peer.WriteTimeout(frame.Bytes())
	if err != nil || n != len(frame.Bytes()) {
		openLog.Printf("Send 'locker open' cmd error: %v\n", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	openLog.Printf("Client[id: %s] <<< 'locker open' cmd", id)
	openLog.Printf("  Bytes: %v", frame.Bytes())
	openLog.Printf("  Rawbytes: %v", utils.HexBytes(frame.Bytes()))

	openLog.Printf("Waiting response from client channel...")

	timer := time.After(time.Second * readWriteTimeout)
	var clientRes []byte
	select {
	case <-timer:
		openLog.Printf("Get response for 'locker open' cmd Timeout")
		utils.JsonResponse(w, http.StatusInternalServerError, RespError, fmt.Sprintf(MsgOpenTimeout, id, channel), nil)
		return
	case clientRes = <-peer.ResponseCh:
	}
	openLog.Printf("Got response for 'locker open' cmd, response message: %v", clientRes)
	openLog.Printf("Raw data: %v", utils.HexBytes(clientRes))
	frame, err = NewFrameFromBytes(clientRes)
	if err != nil {
		errMsg := fmt.Sprintf("[%v-%v] response for 'locker open' cmd error: %s", id, channel, err)
		openLog.Printf(errMsg)
		utils.JsonResponse(w, http.StatusInternalServerError, RespError, errMsg, nil)
		return
	}

	if len(frame.Data) == 3 && frame.Data[0] == Success {
		utils.JsonResponse(w, http.StatusOK, RespOK, fmt.Sprintf(MsgOpenSuccess, id, channel), frame.String())
		openLog.Printf("LockerOpen OK")
	} else {
		utils.JsonResponse(w, http.StatusOK, RespError, fmt.Sprintf(MsgOpenFailed, id, channel), frame.String())
		openLog.Printf("LockerOpen Failed")
	}
}

//srv.Router.HandleFunc("/status/{id}/{channel}",LockerStatus)
func LockerStatus(w http.ResponseWriter, r *http.Request) {
	id, err := getId(r)
	if err != nil {
		statusLog.Printf("%v", err.Error())
		utils.JsonResponse(w, http.StatusBadRequest, RespError, fmt.Sprintf(MsgIdError, mux.Vars(r)["id"]), nil)
		return
	}
	peer := Peers[id]

	channel, err := getChannel(r)
	if err != nil {
		statusLog.Printf("Get channel error: %v", err)
		utils.JsonResponse(w, http.StatusBadRequest, RespError, fmt.Sprintf(MsgChannelError, mux.Vars(r)["channel"]), nil)
	}

	var (
		frame *Frame
	)
	switch ProtocolVersion {
	case Version2G:
		frame = NewFrame(CmdStatus2G, []byte{channel})
	case Version4G:
		frame = NewFrame(CmdStatus4G, []byte{channel})
	}
	n, err := peer.WriteTimeout(frame.Bytes())
	if err != nil || n != len(frame.Bytes()) {
		statusLog.Printf("Send locker status cmd error")
		utils.JsonResponse(w, http.StatusInternalServerError, RespError, "Send locker status cmd error", nil)
		return
	}

	statusLog.Printf("Try to get response from client channel")
	timer := time.After(time.Second * readWriteTimeout)
	var clientRes []byte
	select {
	case <-timer:
		statusLog.Printf("Get response for 'locker status' cmd Timeout")
		utils.JsonResponse(w, http.StatusInternalServerError, RespError, fmt.Sprintf(MsgStatusTimeout, id, channel), nil)
		return
	case clientRes = <-peer.ResponseCh:
	}
	frame, err = NewFrameFromBytes(clientRes)
	if err != nil {
		errMsg := fmt.Sprintf("Response for 'locker status' cmd error: %s", err)
		statusLog.Printf(errMsg)
		w.WriteHeader(http.StatusInternalServerError)
		utils.JsonResponse(w, http.StatusInternalServerError, RespError, errMsg, nil)
		return
	}
	if len(frame.Data) == 3 && frame.Data[0] == Success {
		utils.JsonResponse(w, http.StatusOK, RespOK, fmt.Sprintf(MsgStatusOK, id, channel), frame.String())
		statusLog.Printf("Locker Status OK")
	} else {
		utils.JsonResponse(w, http.StatusOK, RespError, fmt.Sprintf(MsgStatusError, id, channel), frame.String())
		statusLog.Printf("Locker Status Failed")
	}

}

func GetAllPeers(w http.ResponseWriter, r *http.Request) {
	ids := "["
	i := 0

	for _, p := range Peers {
		ids += p.Id
		if i != len(Peers)-1 {
			ids += ","
		}
		i += 1
	}
	ids += "]"

	utils.JsonResponse(w, http.StatusOK, RespOK, MsgPeersOK, ids)

}
